package com.xormedia.httpservice;

import com.xormedia.httpservice.model.ServiceArgs;
import com.xormedia.httpservice.util.DataTransferThrottler;
import com.xormedia.httpservice.util.HandlerExecutor;
import com.xormedia.httpservice.util.NameThreadFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.traffic.ChannelTrafficShapingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.HashedWheelTimer;
import lombok.Getter;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * com.xormedia.httpservice.SimpleHttpServer
 *
 * @author zhikang.peng
 * @date 2017年6月20日上午10:35:33
 * @since 1.0
 */
@Slf4j
public class SimpleHttpServer {

  @Getter
  private ServiceArgs serviceArgs;

  @Getter
  private ServerBootstrap serverBootstrap;

  public static SimpleHttpServer httpServer;

  public SimpleHttpServer(ServiceArgs serviceArgs) {
    this.serviceArgs = serviceArgs;
    httpServer = this;
  }

  public void start() {
    EventLoopGroup mainLoopGroup = new NioEventLoopGroup();
    EventLoopGroup workerLoopGroup = new NioEventLoopGroup();

    serverBootstrap = new ServerBootstrap();
    serverBootstrap.group(mainLoopGroup, workerLoopGroup);
    serverBootstrap.channel(NioServerSocketChannel.class);
    serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel socketChannel) throws Exception {
        //http消息解码器
        ChannelPipeline pipeline = socketChannel.pipeline();
        pipeline.addLast("http-decoder", new HttpRequestDecoder());
        //将消息转为单一的FullHttpRequest或者FullHttpResponse，因为http解码器在每个http消息中会生成多个消息对象
        pipeline.addLast("http-aggregator", new HttpObjectAggregator(65535));
        //对响应消息进行编码
        pipeline.addLast("http-encoder", new HttpResponseEncoder());
        //支持异步发送大大码流，但不占用过多但内存，防止发生Java内存溢出
        pipeline.addLast("http-chunked", new ChunkedWriteHandler());
        pipeline.addLast("http-request-handler", new HttpRequestHandler(serviceArgs));
        pipeline.addLast(new GlobalTrafficShapingHandler(socketChannel.eventLoop().parent(), 1024, 1024));
      }
    });
    try {
      ChannelFuture channelFuture = serverBootstrap.bind(serviceArgs.getPort()).sync();
      channelFuture.channel().closeFuture().sync();
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    } finally {
      mainLoopGroup.shutdownGracefully();
      workerLoopGroup.shutdownGracefully();
    }

  }

}
